﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Text;
using FieldDevice;

using FieldLib.DataAccess;
using FieldLib.Comm;
using Semantics;
using System.Net.Sockets;

namespace FieldDevice
{
    public class DeviceManager : Graph
    {
        public DeviceManager()
        {
            this.FieldReadLog = new FieldLib.DataAccess.CoFieldReads();
        }
        public FieldLib.DataAccess.IFieldReadLog FieldReadLog;
        public ModBus.ModBusIO ModBusIO = new ModBus.ModBusIO();
        static DeviceManager _devicemanager;
        public static DeviceManager GlobalDeviceManager
        {
            get
            {
                if (_devicemanager == null)
                    _devicemanager = new DeviceManager();
                return _devicemanager;
            }
        }

        ModBus.ModBusTCPServer ModBusTCPServer;

        internal UI.UIManager UIManager;
        public void OpenDevice(Device device)
        {
            this.UIManager.OpenDevice(device);
        }

        public void MonitorDevice(Device device)
        {
            this.UIManager.monitorDevice(device);
        }
        
        public Device GetDevice(uint address)
        {
            Node n = base.ResolveNode((int)address);
            if (n == null)
                return null;
            else
                return (Device)n;
        }

        /// <summary>
        /// 通过设备名找到设备
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public Device GetDevice(string name)
        {
            return (Device)base.ResolveNode(name);
        }

        public void CreateDevices()
        {
            base.Clear();
            switch (FieldLib.SystemConfig.GlobalSystemConfig.DeviceEmulation)
            {
                case FieldLib.SystemConfig.EnumDeviceEmulation.Design:
                case FieldLib.SystemConfig.EnumDeviceEmulation.Field:
                    LoadDevicesFromDatabase();
                    break;
                default:
                    //this.Devices.Add(1, new Devices.DeviceACR120EL(1, "ACR120EL"));
                    //this.Devices.Add(99, new Devices.DeviceLB10(99, "LB10"));
                    //this.Devices.Add(8, new Devices.DevicePM800(8, "PM800"));
                    break;
            }
        }
        public Storage Storage = new Storage();
        public void LoadDevicesFromDatabase()
        {
            if (!this.IsCommInitialized)
            {
                throw new Exception("Comm is not initialized!");
            }
            FieldDataSet.DevicesDataTable devices = this.Storage.LoadDevices();
            foreach (FieldDataSet.DevicesRow devicerow in devices)
            {
                CreateDevice(devicerow);
            }
        }

        public Device CreateDevice(FieldDataSet.DevicesRow devicerow)
        {
            if (devicerow.IsModelNull())
                return null;
            Device device = null;
            switch (devicerow.Model.Trim())
            {
                case "EM400":
                    device = new Devices.DeviceEM400((byte)devicerow.ModeAddr);
                    break;
                case "LB10":
                    device = new Devices.DeviceLB10((byte)devicerow.ModeAddr);
                    break;
                case "YAAOA1":
                    device = new Devices.DeviceYaaoA1DC((byte)devicerow.ModeAddr);
                    break;
                case "REF542PLUS":
                    device = new Devices.DeviceREF542Plus((byte)devicerow.ModeAddr);
                    break;
                case "ACR120":
                    device = new Devices.DeviceACR120EL((byte)devicerow.ModeAddr);
                    break;
                case "ACR320":
                    device = new Devices.DeviceACR330ELH((byte)devicerow.ModeAddr);
                    break;
                case "EmaxE3":
                    device = new Devices.DeviceEmaxE3((byte)devicerow.ModeAddr);
                    break;
                case "PM800":
                    device = new Devices.DevicePM800((byte)devicerow.ModeAddr);
                    break;
                case "REF615":
                    device = new Devices.DeviceREF615((byte)devicerow.ModeAddr);
                    break;
                case "PM5350":
                    device = new Devices.DevicePM5350((byte)devicerow.ModeAddr);
                    break;
                case "PMC43M":
                    device = new Devices.DevicePMC43M((byte)devicerow.ModeAddr);
                    break;
                default:
                    return null;
            }
            if (device == null)
                return null;
            device.DeviceName = devicerow.DeviceName.TrimEnd();
            device.IPAddress = devicerow.IPAddress.TrimEnd();
            device.CommPortName = devicerow.Comm;
            device.DeviceModel = devicerow.Model.TrimEnd();
            device.Enable = devicerow.Enable;
            if (!devicerow.IsConfigNull())
            {
                object o = Semantics.Serialization.XMLSerial.ObjectFromXml(devicerow.Config);
                device.Config = (Device.DeviceConfigBase)o;
            }
            if (!devicerow.IsDesciptionNull())
                device.Description = devicerow.Desciption.TrimEnd();
            this.CommHub.SetNCP(device);
            //if (this.IsCommInitialized)
            //{
            //    this.Devices.Add(device.NCPAddress, device);
            //}
            //this.DevicesByNames.Add(device.DeviceName, device);
            base.EnrollNode(device);
            return device;
        }

        public bool IsCommInitialized =false;
        public void UpdateDevices()
        {
            foreach (Node node in base.Nodes.Values)
            {
                Device device = (Device)node;
                if (device.Enable)
                {
                    try
                    {
                        device.DebugReads();
                    }
                    catch (Exception exp)
                    {
                        base.Warn(new ReadDeviceWarning(device, "read device error"));
                    }
                }
            }
        }

        public class ReadDeviceWarning : Semantics.Warning
        {
            public ReadDeviceWarning(Device device, string message)
                :base(message)
            {
                this.Device = device;
            }

            public Device Device;

            public override string ToString()
            {
                return "ReadDeviceWarning:" + this.Device + Message;
            }
        }

        public void Startup(Form form)
        {
            this.UIManager = new FieldDevice.UI.UIManager(form);
            this.InitializeCommHub();
            this.LoadDevicesFromDatabase();
            StartComServer();
            System.Threading.Thread.Sleep(1000);
            this.OpenCommHub();
            if(FieldLib.SystemConfig.GlobalSystemConfig.ScheduleManner!=FieldLib.SystemConfig.EnumScheduleManner.Interactive)
                this.StarupBackThreads();//在OnTimer或BackThread两种模式下都需要启动后台时钟线程
            //FieldLib.FieldSystem.g_FieldSystem.Initialize();
            this.ModBusTCPServer = new FieldDevice.ModBus.ModBusTCPServer(this);
            this.ModBusTCPServer.Start();
        }

        void StartComServer()
        {
            bool comserverrunning = false;
            try
            {
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.Connect("127.0.0.1", 701);
                if (socket.Connected)
                    comserverrunning = true;
            }
            catch (SocketException exp)
            {
                comserverrunning = false;
            }
            if (!comserverrunning)
            {
                String filename = FieldLib.SystemConfig.GlobalSystemConfig.ComServerExeFile;
                if (!System.IO.File.Exists(filename))
                    throw new Exception("数据服务器程序 '" + filename + "' 没有找到!");
                System.Diagnostics.Process.Start(filename);
            }
        }
        public ICollection<SerialPort> GetSerials()
        {
            return this.CommHub.GetSeriaPortEnumerator();
        }
        CommHub CommHub;
        public void InitializeCommHub()
        {
            this.CommHub = new CommHub();
            this.CommHub.Intialize();
            this.IsCommInitialized = true;
        }

        public bool IsCommOpen
        {
            get
            {
                if (this.CommHub == null)
                    return false;
                return this.CommHub.IsOpen;
            }
        }
        public void OpenCommHub()
        {
            if (this.CommHub == null || !this.IsCommInitialized)
            {
                throw new Exception("Please call InitializeCommHub at first!");
            }
            this.CommHub.Open();
        }

        public void OnOneSecondTimer()
        {
            this.UIManager.OnTimer();
            this.CommHub.OnOneSecondTimer();
        }

        public void ClearDirty()
        {
            foreach (Node node in base.Nodes.Values)//this.Devices.Values)
            {
                Device device = (Device)node;
                if (device.Dirty)
                    device.Dirty = false;
            }
        }
        internal void StarupBackThreads()
        {
            if (this.CommHub == null)
                throw new Exception("CommHub is null");
            CommHub.StarupBackThreads();
        }

        public void Finallize()
        {
            if (ModBusTCPServer != null)
                this.ModBusTCPServer.Stop();
            if (this.CommHub != null)
            {
                this.CommHub.Close();
            }
        }
    }
}
